package cn.dj.user.service.impl;

import cn.dj.basic.exception.BusinessException;
import cn.dj.basic.util.Md5Utils;
import cn.dj.basic.util.StrUtils;
import cn.dj.org.domain.Employee;
import cn.dj.org.domain.Shop;
import cn.dj.user.domain.Logininfo;
import cn.dj.user.domain.User;
import cn.dj.user.mapper.LogininfoMapper;
import cn.dj.user.mapper.UserMapper;
import cn.dj.user.service.IUserService;
import cn.dj.basic.service.impl.BaseServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.util.Map;

/**
 * 业务实现类：用户
 */
@Service
public class UserServiceImpl extends BaseServiceImpl<User> implements IUserService {
    @Autowired//注入
    private UserMapper userMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private LogininfoMapper logininfoMapper;
    @Autowired
    private JavaMailSender javaMailSender;

    @Override
    public void phoneRegister(Map<String, String> map) {
       /*前端传递的，可以选择性获取 imageCode:'',//图形验证码
                phone:'18982322687',//手机号 - 用来v-model做了双向绑定
                phoneCode:'',
                pwd:'',//传递到后端的数据需要做双向绑定
                rePwd:''//前端得到页面中输入的数据，一定要进行双向绑定
*/
        //【注册时不需要图形验证码的判断，故可以不获取】
        String phone = map.get("phone");
        String phoneCode = map.get("phoneCode");//页面传来的，用的map接收对象，那么根据key也就是属性名来得到值
        String pwd = map.get("pwd");
        String rePwd = map.get("rePwd");
        //一：校验
        //1.空值
        if (StringUtils.isEmpty(phone)||StringUtils.isEmpty(phoneCode)||StringUtils.isEmpty(rePwd)
        ||StringUtils.isEmpty(pwd)){
            throw new BusinessException("信息不能为空");
        }
        //2.密码是否一致
        if (!pwd.equals(rePwd)){
            throw new BusinessException("两次密码不一致");
        }
        //3.手机验证码是否过期，是否正确
            //obj是 验证码：时间戳的形式 - redis中的
        Object obj = redisTemplate.opsForValue().get("register:" + phone);
        if (obj==null){
            throw new BusinessException("手机验证码过期");
        }
        //redis中手机验证码的存储格式【业务键：手机号码 - 验证码：时间戳】
        if (!phoneCode.equals(obj.toString().split(":")[0])){
            throw new BusinessException("手机验证码错误");
        }

        //二.添加到数据库
        //当将一个对象转换成另外一个对象的时候，而且代码量多的时候，就用obj2obj的方式
            //2指的to
        User user = map2User(map);//map对象转换成user对象
        Logininfo logininfo = user2Logininfo(user);//转换对象后，这样就可以拷贝属性的方式直接赋值存值
        //1.先添加t_logininfo- 这样才有自增长id
        logininfoMapper.save(logininfo);
        //2.再添加t_user
        user.setLogininfoId(logininfo.getId());
        userMapper.save(user);
    }

    @Override
    public void emailRegister(Map<String, String> map) throws MessagingException {//邮箱校验和验证码不同，验证码属于basic。而邮箱属于用户user，所以在这里判断是否注册过
       /* email:'',
        pwd:'',
        rePwd:''*/
        String email = map.get("email");
        String pwd = map.get("pwd");
        String rePwd = map.get("rePwd");

        //一：校验
        //1.空值
        if (StringUtils.isEmpty(email) ||StringUtils.isEmpty(pwd) ||StringUtils.isEmpty(rePwd)){//isEmpty是空值返回true
                throw new BusinessException("信息不能为空");
        }
        //2.密码是否一致
        if (!pwd.equals(rePwd)){
            throw new BusinessException("两次密码不一致");
        }
        //3.该邮箱是否已经注册过
        User dbUser = userMapper.loadByEmail(email);
        if (dbUser!=null){//根据邮箱能找到该用户，说明该用户已经存在
            throw new BusinessException("该用户已经注册过，若忘记密码，请联系管理员处理");
        }
        //二.添加到数据库
        //当将一个对象转换成另外一个对象的时候，而且代码量多的时候，就用obj2obj的方式
            //2指的to
        User user = map2UserEmail(map);//map对象转换成user对象
        Logininfo logininfo = user2LogininfoEmail(user);//转换对象后，这样就可以拷贝属性的方式直接赋值存值
        //1.先添加t_logininfo- 这样才有自增长id
        logininfoMapper.save(logininfo);
        //2.再添加t_user
        user.setLogininfoId(logininfo.getId());
        userMapper.save(user);

        //三：添加进去后，同时发送邮箱。自己激活使用状态
        //创建复杂邮件对象
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        //发送复杂邮件的工具类
        //true - 能够添加附件
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true,"utf-8");
        helper.setFrom("757479956@qq.com");//平台的邮箱
        helper.setSubject("用户状态激活邮件");
        //true - 能够在内容中编写html标签 - 会解析
        /*
        127.0.0.1也就是localhost，因为QQ邮箱用localhost无法进行跳转，所以这里使用127.0.0.1将可以跳转
        */
        helper.setText("<h1>点击链接，激活用户状态!!!</h1><a href='http://127.0.0.1:8080/user/active/"
                +user.getId()+"'>点击该链接激活</a>",true);
        //收件人
        helper.setTo(email);//该邮件是页面注册输入的邮箱 - 要真实有效
        javaMailSender.send(mimeMessage);//发送邮件

    }

    @Override
    public void activeId(Long id) {
        //根据id找到用户
        User user = userMapper.loadById(id);
        //找登录用户信息
        Logininfo logininfo = logininfoMapper.loadById(user.getLogininfoId());

        user.setState(1);//设置用户状态为激活
        logininfo.setDisable(true);//设置为启用状态

        logininfoMapper.update(logininfo);//更新状态;
        userMapper.update(user);//更新用户激活状态
    }

    private Logininfo user2LogininfoEmail(User user) {
        Logininfo logininfo = new Logininfo();
        //根据属性名同名【属性同名原则进行copy】进行属性值的复制赋值
        //根据属性同名原则：【id自增长】
        BeanUtils.copyProperties(user,logininfo);
        //没有顾及到的，还需要另外设置
        logininfo.setType(1);//用户邮箱注册- 所以状态应该设置为1【0是管理员】
        logininfo.setDisable(false);//手机注册默认启用
        return logininfo;
    }

    private User map2UserEmail(Map<String, String> map) {
        //需要User就给它User
        User user = new User();
        String email = map.get("email");
        user.setUsername(email);//邮箱码注册这里就是邮箱是用户名
        user.setEmail(email);
        //没有电话就不设置
        //盐值salt - 生成32 位随机盐值
        String salt = StrUtils.getComplexRandomString(32);
        //加密加盐【md5技术是不可逆的】
        String md5Pwd = Md5Utils.encrypByMd5(map.get("pwd") + salt);//顺序不能变，这里一般先加密再加盐
        user.setSalt(salt);
        user.setPassword(md5Pwd);//加密加盐后的密码存入
        //需要通过邮箱激活state-->1
        user.setState(0);//注册后就给它默认禁用
        return user;
    }

    private Logininfo user2Logininfo(User user) {//打开相应的数据库表对照着字段看着来
        Logininfo logininfo = new Logininfo();
        //根据属性名同名【属性同名原则进行copy】进行属性值的复制赋值
        //根据属性同名原则：【id自增长】
        BeanUtils.copyProperties(user,logininfo);
        //没有顾及到的，还需要另外设置
        logininfo.setType(1);//用户手机号注册- 所以状态应该设置为1【0是管理员】
        logininfo.setDisable(true);//手机注册默认启用
        return logininfo;
    }

    private User map2User(Map<String, String> map) {
        //需要User就给它User
        User user = new User();
        String phone = map.get("phone");
        user.setUsername(phone);//手机号码注册这里就是手机号是用户名【邮箱同理】
       user.setPhone(phone);
       //没有邮箱就不设置
        //盐值salt - 生成32 位随机盐值
        String salt = StrUtils.getComplexRandomString(32);
        //加密加盐【md5技术是不可逆的】
        String md5Pwd = Md5Utils.encrypByMd5(map.get("pwd") + salt);//顺序不能变，这里一般先加密再加盐
        user.setSalt(salt);
        user.setPassword(md5Pwd);//加密加盐后的密码存入
        user.setState(1);//注册后就给它默认启用
        return user;
    }

    /**
     * 重写删除方法，为了删除用户信息的时候，同时删除t_logininfo表里的信息
     * @param id
     */
    @Transactional//事务管理
    @Override
    public void del(Long id) {
        User user = userMapper.loadById(id);
        //删除t_logininfo表里的信息
        logininfoMapper.del(user.getLogininfoId());
        //删除t_employee表里的信息
        super.del(id);//调用父类中的删除方法，根据id删除用户信息
    }
    /**
     * 重写添加方法，为了添加t_user的时候，也会添加t_logininfo
     * @param user
     */
    @Transactional//管理事务
    @Override
    public void save(User user) {
        //处理盐值和密码s
        String salt = StrUtils.getComplexRandomString(32);
        user.setSalt(salt);
            //加密加盐
        String md5Pwd = Md5Utils.encrypByMd5(user.getPassword() + salt);//加密加盐
        user.setPassword(md5Pwd);
        //先添加logininfo
        Logininfo logininfo = new Logininfo();
        //同名属性原则：
        BeanUtils.copyProperties(user,logininfo);
        logininfo.setType(1);//管理员1【用户0】
        logininfo.setDisable(true);
        logininfoMapper.save(logininfo);//自增长id

        //再添加user的数据
        user.setLogininfoId(logininfo.getId());
        super.save(user);
    }

    /**
     * 重写修改方法，为了修改t_user的时候，也会修改t_logininfo
     * @param user
     */
    @Transactional//事务管理
    @Override
    public void update(User user) {//前端传过来的user是没有登陆信息id
        //处理盐值和密码
        String salt = StrUtils.getComplexRandomString(32);//随机生成32位盐值
        String md5Pwd = Md5Utils.encrypByMd5(user.getPassword() + salt);//加密加盐
        user.setSalt(salt);
        user.setPassword(md5Pwd);

        //获取修改前的用户信息
        User oldUser = userMapper.loadById(user.getId());//获取之前的信息是为了获取登陆信息logininfo

        //根据oldUser设置user中没有的信息
        user.setLogininfoId(oldUser.getLogininfoId());//登录信息id不变【一对一】
        //调用父类的方法，更新t_user表
        super.update(user);//有新的内容以及唯一对应的登录信息等数据

        //修改的同时修改登录信息
        Logininfo oldLogininfo = logininfoMapper.loadById(oldUser.getLogininfoId());
        //属性同名原则：
        BeanUtils.copyProperties(user,oldLogininfo);
        //id不自增，设置成以前的id，还是这条id的登录信息对应这个用户
        oldLogininfo.setId(oldUser.getLogininfoId());
        //修改t_logininfo表
        logininfoMapper.update(oldLogininfo);//需要先前的id，因为根据id进行修改
    }
}
